package com.hello.system.aspect;

import com.hello.common.core.web.domain.AjaxResult;
import com.hello.system.annotation.ContentSecurity;
import com.hello.system.service.WxContentSecurityService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Map;

/**
 * 内容安全检测切面
 * 
 * @author hello
 */
@Aspect
@Component
@Slf4j
public class ContentSecurityAspect {
    
    @Autowired
    private WxContentSecurityService contentSecurityService;
    
    /**
     * 定义切点：标记了ContentSecurity注解的方法
     */
    @Pointcut("@annotation(com.hello.system.annotation.ContentSecurity)")
    public void contentSecurityPointcut() {}
    
    /**
     * 环绕通知：在方法执行前检测内容安全
     */
    @Around("contentSecurityPointcut()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        // 获取方法签名
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        
        // 获取ContentSecurity注解
        ContentSecurity annotation = method.getAnnotation(ContentSecurity.class);
        if (annotation == null) {
            return joinPoint.proceed();
        }
        
        // 获取需要检测的参数和字段
        String paramName = annotation.paramName();
        String fieldName = annotation.fieldName();
        
        // 获取请求中的参数值
        Object[] args = joinPoint.getArgs();
        Object param = null;
        String content = null;
        
        // 尝试从方法参数中获取对象
        for (Object arg : args) {
            if (arg != null) {
                if (paramName.isEmpty() || arg.getClass().getSimpleName().equalsIgnoreCase(paramName)) {
                    param = arg;
                    break;
                }
            }
        }
        
        // 如果找到了参数对象，尝试获取其字段值
        if (param != null && !fieldName.isEmpty()) {
            try {
                // 如果是Map类型
                if (param instanceof Map) {
                    content = (String) ((Map) param).get(fieldName);
                } else {
                    // 尝试通过反射获取字段值
                    Field field = getField(param.getClass(), fieldName);
                    if (field != null) {
                        field.setAccessible(true);
                        content = (String) field.get(param);
                    }
                }
            } catch (Exception e) {
                log.error("获取字段值失败", e);
            }
        }
        
        // 如果未找到内容，直接放行
        if (content == null || content.isEmpty()) {
            log.warn("未找到需要检测的内容，参数名: {}, 字段名: {}", paramName, fieldName);
            return joinPoint.proceed();
        }
        
        // 获取请求中的openid
        String openid = null;
        try {
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            if (attributes != null) {
                HttpServletRequest request = attributes.getRequest();
                openid = request.getHeader("X-WX-OPENID"); // 从请求头中获取openid
            }
        } catch (Exception e) {
            log.warn("获取openid失败", e);
        }
        
        // 检测内容安全
        Map<String, Object> result = contentSecurityService.checkText(content, openid);
        
        // 如果检测不通过，返回错误结果
        if (!(Boolean) result.get("pass")) {
            String message = (String) result.get("message");
            log.info("内容安全检测未通过: {}", message);
            return AjaxResult.error("内容安全检测未通过: " + message);
        }
        
        // 检测通过，执行原方法
        return joinPoint.proceed();
    }
    
    /**
     * 递归获取类的字段
     */
    private Field getField(Class<?> clazz, String fieldName) {
        if (clazz == null) {
            return null;
        }
        
        try {
            return clazz.getDeclaredField(fieldName);
        } catch (NoSuchFieldException e) {
            // 在父类中查找
            return getField(clazz.getSuperclass(), fieldName);
        }
    }
} 